package com.recSystem.Service.ServiceImpl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.recSystem.Entity.Converters.UserConverter;
import com.recSystem.Entity.DO.*;
import com.recSystem.Entity.DTO.*;
import com.recSystem.Entity.DTO.Param.*;
import com.recSystem.Entity.POJO.HttpResponse;
import com.recSystem.Entity.DTO.DataUserDTO;
import com.recSystem.Entity.DTO.UserInfoDTO;
import com.recSystem.Mapper.*;
import com.recSystem.Service.AuthorService;
import com.recSystem.Service.PaperService;
import com.recSystem.Service.UserService;
import com.recSystem.Utils.Constant;
//import com.recSystem.Utils.SHA256Util;
import com.recSystem.Utils.PageParser;
import com.recSystem.Utils.SHA256Util;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.recSystem.Utils.TokenParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserDO> implements UserService {

    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);

    private final PaperService paperService;
    private final AuthorService authorService;
    private final AuthorMapper authorMapper;
    private final InterestMapper interestMapper;
    private final IdentitiesMapper identitiesMapper;
    private final SearchMapper searchMapper;
    public UserServiceImpl(PaperService paperService, AuthorService authorService, AuthorMapper authorMapper, InterestMapper interestMapper, IdentitiesMapper identitiesMapper, SearchMapper searchMapper) {
        this.paperService = paperService;
        this.authorService = authorService;
        this.authorMapper = authorMapper;
        this.interestMapper = interestMapper;
        this.identitiesMapper = identitiesMapper;
        this.searchMapper = searchMapper;
    }

    // 用户注册
    public HttpResponse<UserRegisterDTO> addUser(UserRegisterParam user) {
        String username = user.getUsername();
        String password = user.getPassword();
        String salt = user.getSalt();
        String identity = user.getIdentity();
        String email = user.getEmail();
//        log.debug(username);
        if (query().eq("username", username).one() != null) {
            return new HttpResponse<>(new StatusDTO(21, "用户名已被占用"), null);
        } else if (username.length() >= 16 || username.length() < 1) {
            return new HttpResponse<>(new StatusDTO(22, "用户名格式错误"), null);
        } else if (password.length() < 8 || password.length() > 16) {
            return new HttpResponse<>(new StatusDTO(42, "密码格式错误"), null);
        } else {
            UserDO userInfo = new UserDO();
            userInfo.setUsername(username);
//            userInfo.setPassword(SaltMD5Util.MD5(password));
            //SHA256加盐加密
            userInfo.setPassword(SHA256Util.getSHA256StrJava(password+salt));
            userInfo.setSalt(salt);
            userInfo.setLastLogin(String.valueOf(-1));
            userInfo.setEmail(email);
            baseMapper.insert(userInfo);
            UserDO userDO = query().eq("username", userInfo.getUsername()).one();
            Integer userId = userDO.getUserId();

            String token = TokenParser.generateToken(userId);

            long currentTimeStamp = System.currentTimeMillis() / 1000;
            String expireTime = String.valueOf(currentTimeStamp + Constant.expire_time);

            log.debug("{}用户注册成功", username);
            return new HttpResponse<>(new StatusDTO(0, "注册成功"),
                    new UserRegisterDTO(token, expireTime));
        }
    }

    // 用户登录
    public HttpResponse<UserLoginDTO> authenticateUser(UserLoginParam user) {
        String username = user.getLogin();
//        前端传过来的是明文
        String password = user.getPassword();
        Boolean rememberMe = user.isRememberMe();

        //查询是否存在
        UserDO userInfo = query()
                .eq("username", username)
                .one();

        if (userInfo == null) {
            return new HttpResponse<>(new StatusDTO(1, "用户不存在"), null);
        }
        //判断是否密码正确
        else {
            // 数据库中存储的加盐加密后的密码
            String passwordInfo = userInfo.getPassword();
            String salt = userInfo.getSalt();
            // 对输入的密码进行SHA256加盐加密，再与数据库里的密码比较
            String Pass2SHA256 = SHA256Util.getSHA256StrJava(password+salt);
            // 判断是否相等
            boolean passwordFlag = Pass2SHA256.equals(passwordInfo);
            // 如果根据账号查询和校验加密密码失败,则返回错误信息
            // !!！正式上线记得开启
            if (!passwordFlag) {
                return new HttpResponse<>(new StatusDTO(2, "密码错误"), null);
            }

            //全部认证成功，返回正确并存入last_login时间
            String lastLogin = String.valueOf(System.currentTimeMillis() / 1000L);
            userInfo.setLastLogin(lastLogin);
            userInfo.setRememberMe(rememberMe);
            saveOrUpdate(userInfo);

            String token = TokenParser.generateToken(userInfo.getUserId());
            log.debug("用户：{}登录成功，返回token--{}", username, token);

            return new HttpResponse<>(new StatusDTO(0, "登录成功"), new UserLoginDTO(token));
        }
    }

    // 获取用户信息
    public HttpResponse<DataUserDTO> getUserInfo(String token) {
        if (token == null) {
            return new HttpResponse<>(new StatusDTO(1, "缺少token"), null);
        }
        Integer id = TokenParser.parse(token);
        UserDO user = query().eq("user_id", id).one();
        if (user == null) {
            return new HttpResponse<>(new StatusDTO(1, "token不合法"), null);
        }

        UserInfoDTO userInfoDTO = UserConverter.INSTANCE.userToUserInfoDTO(user);

        DataUserDTO data = new DataUserDTO(userInfoDTO);

        return new HttpResponse<>(new StatusDTO(0, "用户信息获取成功"), data);
    }

    // 修改用户信息
    public HttpResponse<DataErrorsDTO> modifyUserInfo(UserModifyParam user, String token) {
        String username = user.getUsername();
        String email = user.getEmail();

        Integer userId = TokenParser.parse(token);
        UserDO userInfo = query().eq("user_id", userId).one();

        int reCode = 0;
        List<UserModifyDTO> errors = new ArrayList<>();
        if (username != null) {
            // 验证用户名是否合法
            if (username.length() >= 16 || username.length() < 1) {
                reCode++;
                errors.add(new UserModifyDTO("username", "用户名格式不正确"));
            } else userInfo.setUsername(username);
        }
        if (email != null && !email.equals(userInfo.getEmail())) {
            // 验证邮箱是否合法
            if (query().eq("email", email).one() != null) {
                reCode++;
                errors.add(new UserModifyDTO("email", "电子邮件地址已被占用"));
            } else userInfo.setEmail(email);
        }

        userInfo.setRealname(user.getRealname());
        userInfo.setGender(user.getGender());
        userInfo.setMajor(user.getMajor());
        userInfo.setWorkplace(user.getWorkplace());
        userInfo.setResearchfield(user.getResearchfield());
        userInfo.setPhone(user.getPhone());

        saveOrUpdate(userInfo);

        if (reCode == 0) {
            return new HttpResponse<>(new StatusDTO(reCode, "用户信息修改成功"), new DataErrorsDTO(errors));
        } else {
            return new HttpResponse<>(new StatusDTO(reCode, "有" + reCode + "个字段修改失败"), new DataErrorsDTO(errors));
        }
    }

    // 获取用户浏览的论文信息
    public HttpResponse<UserBrowsingPageDTO> getBrowsing(UserBehaviorParam userFavoriteParam, String token) {
        Integer userId = TokenParser.parse(token);
        // 每页大小
        int maxLength = userFavoriteParam.getMaxLength();
        // 页号，从1开始
        int offset = userFavoriteParam.getOffset();

        IPage<PaperBrowsingDTO> paperBrowsingDTOIPage = paperService.getBrowsingPapersPage(userId, maxLength, offset);
        UserBrowsingPageDTO pageDTO = new UserBrowsingPageDTO((int) paperBrowsingDTOIPage.getTotal(), paperBrowsingDTOIPage.getRecords());
        return new HttpResponse<>(new StatusDTO(Constant.SUC_CODE, Constant.SUC_GET_BROWSING_INFO), pageDTO);
    }

    // 获取用户收藏的论文信息
    public HttpResponse<UserFavoritePageDTO> getFavorite(UserBehaviorParam userFavoriteParam, String token) {
        Integer userId = TokenParser.parse(token);
        // 每页大小
        int maxLength = userFavoriteParam.getMaxLength();
        // 页号，从1开始
        int offset = userFavoriteParam.getOffset();

        IPage<PaperFavoriteDTO> paperFavoriteDtoPage = paperService.getFavoritePapersPage(userId, maxLength, offset);
        UserFavoritePageDTO pageDTO = new UserFavoritePageDTO((int) paperFavoriteDtoPage.getTotal(), paperFavoriteDtoPage.getRecords());
        return new HttpResponse<>(new StatusDTO(Constant.SUC_CODE, Constant.SUC_GET_FAVORITE_INFO), pageDTO);
    }


    public HttpResponse userLogOut() {
        return new HttpResponse(new StatusDTO(Constant.SUC_CODE, "退出登录成功"), null);
    }

    // 修改密码
    public HttpResponse modifyUserPassword(UserChangePasswordParam param, String token) {
        Integer userId = TokenParser.parse(token);
        UserDO userDO = baseMapper.selectById(userId);
        // 数据库中存储的加盐加密后的密码
        String passwordInfo = userDO.getPassword();
        String salt = userDO.getSalt();
        // 对输入的密码进行SHA256加盐加密，再与数据库里的密码比较
        String Pass2SHA256 = SHA256Util.getSHA256StrJava(param.getOldPassword()+salt);
        // 判断是否相等
        boolean passwordFlag = Pass2SHA256.equals(passwordInfo);

        if (!passwordFlag) {
            // 判断旧密码错误
            return new HttpResponse(new StatusDTO(1, "旧密码不匹配"), null);
        } else {
            //SHA256加盐加密
            userDO.setPassword(SHA256Util.getSHA256StrJava(param.getNewPassword()+salt));
            baseMapper.updateById(userDO);
            return new HttpResponse(new StatusDTO(0, "密码修改成功"), null);
        }
    }

    @Override
    public HttpResponse validateUsername(ValidateParam param) {
        String username = param.getUsername();
        if (query().eq("username", username).exists()) {
            return new HttpResponse(new StatusDTO(1, "用户名已被占用"), null);
        } else if (username.length() >= 16 || username.length() < 1) {
            return new HttpResponse(new StatusDTO(2, "用户名格式错误"), null);
        } else {
            return new HttpResponse(new StatusDTO(0, "用户名可用"), null);
        }
    }

    @Override
    public HttpResponse validateEmail(ValidateParam param) {
        String email = param.getEmail();
        if (query().eq("email", email).exists()) {
            return new HttpResponse(new StatusDTO(1, "电子邮件地址已被占用"), null);
        } else if (email.length() < 3) {
            return new HttpResponse(new StatusDTO(2, "电子邮件地址格式错误"), null);
        } else {
            return new HttpResponse(new StatusDTO(0, "电子邮件地址可用"), null);
        }
    }

    @Override
    public HttpResponse test(int originUserId) {

        return new HttpResponse(new StatusDTO(Constant.SUC_CODE, Constant.SUC_GET_REC), null);
    }

    @Override
    public HttpResponse deleteSearch(SearchIdParam param, String token) {
        int userId = TokenParser.parse(token);
        int searchId = param.getSearchId();

        HashMap<String, Integer> queryMap = new HashMap<>(2);
        queryMap.put("user_id", userId);
        queryMap.put("search_id", searchId);
        searchMapper.delete(new QueryWrapper<SearchDO>().allEq(queryMap));

        return new HttpResponse(new StatusDTO(0, "删除检索记录成功"), null);
    }

    @Override
    public HttpResponse addSearch(UserSearchParam param, String token) {
        int userId = TokenParser.parse(token);
        String search = param.getSearchStr();
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String formattedDateTime = now.format(formatter);
        SearchDO searchDO = new SearchDO(0, userId, search, formattedDateTime, 0);
        searchMapper.insert(searchDO);
        return new HttpResponse(new StatusDTO(0, "记录检索历史成功"), null);
    }

    @Override
    public HttpResponse<UserSearchPageDTO> getSearch(UserBehaviorParam userBehaviorParam, String token) {
        Integer userId = TokenParser.parse(token);
        int maxLength = userBehaviorParam.getMaxLength();
        int offset = userBehaviorParam.getOffset();
        IPage<SearchDO> pageInfo = PageParser.getPage(maxLength, offset);
        QueryWrapper<SearchDO> searchDOQueryWrapper = new QueryWrapper<>();
        IPage<SearchDO> searchRelationsPage = searchMapper.
                selectPage(pageInfo, searchDOQueryWrapper.eq("user_id", userId));
        IPage<UserSearchDTO> userSearchDTOIPage = searchRelationsPage.convert(searchDO -> {
            UserSearchDTO userSearchDTO = new UserSearchDTO();
            userSearchDTO.setSearch_id(searchDO.getSearchId());
            userSearchDTO.setSearch_str(searchDO.getSearchStr());
            userSearchDTO.setSearch_time(searchDO.getSearchTime());
            return userSearchDTO;
        });
        UserSearchPageDTO pageDTO = new UserSearchPageDTO((int) userSearchDTOIPage.getTotal(), userSearchDTOIPage.getRecords());
        return new HttpResponse<>(new StatusDTO(0, "检索历史获取成功"), pageDTO);
    }

    public boolean isInterest(Integer userId, Integer authorId) {
        HashMap<String, Integer> queryMap = new HashMap<>(2);
        queryMap.put("user_id", userId);
        queryMap.put("author_id", authorId);
        return interestMapper.exists(new QueryWrapper<InterestDO>().allEq(queryMap));
    }

    @Override
    public HttpResponse modifyInterest(AuthorInterestParam param, String token) {
        int userId = TokenParser.parse(token);
        int authorId = param.getAuthorId();

        if (isInterest(userId, authorId)) {
            // 已被关注
            HashMap<String, Integer> queryMap = new HashMap<>(2);
            queryMap.put("user_id", userId);
            queryMap.put("author_id", authorId);
            interestMapper.delete(new QueryWrapper<InterestDO>().allEq(queryMap));
        } else {
            // 获取当前日期和时间
            LocalDateTime now = LocalDateTime.now();
            // 定义日期时间格式
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            // 格式化日期时间为字符串
            String formattedDateTime = now.format(formatter);
            InterestDO interestDO = new InterestDO(0, userId, authorId, formattedDateTime);
            interestMapper.insert(interestDO);
        }
        return new HttpResponse(new StatusDTO(0, "修改收藏状态成功"), null);
    }

    @Override
    public HttpResponse<UserInterestPageDTO> getInterest(UserBehaviorParam userInterestParam, String token) {
        Integer userId = TokenParser.parse(token);
        // TODO 分页信息未必有
        // 每页大小
        int maxLength = userInterestParam.getMaxLength();
        // 页号，从1开始
        int offset = userInterestParam.getOffset();

        IPage<AuthorInterestDTO> authorInterestDTOIPage = authorService.getInterestAuthorsPage(userId, maxLength, offset);
        UserInterestPageDTO pageDTO = new UserInterestPageDTO((int) authorInterestDTOIPage.getTotal(), authorInterestDTOIPage.getRecords());
        return new HttpResponse<>(new StatusDTO(Constant.SUC_CODE, Constant.SUC_GET_INTEREST_INFO), pageDTO);
    }

    @Override
    public HttpResponse<List> getIdentities() {
        List<IdentitiesDO> identitiesDOS= identitiesMapper.selectList(null);
        IdentitiesDTO identitiesDTO = new IdentitiesDTO(identitiesDOS);
        return new HttpResponse<List>(new StatusDTO(Constant.SUC_CODE, "职称信息获取成功"), identitiesDOS);
    }
}
